package com.zofer.study.stream;

import com.zofer.study.stream.entity.Dish;

import java.util.*;

/**
 * 并行流和串行流
 */
public class StreamTest04 {

    static List<Dish> menu = Arrays.asList(
            new Dish("pork", false, 800, Dish.Type.MEAT),
            new Dish("beef", false, 700, Dish.Type.MEAT),
            new Dish("chicken", false, 400, Dish.Type.MEAT),
            new Dish("french fries", true, 530, Dish.Type.OTHER),
            new Dish("rice", true, 350, Dish.Type.OTHER),
            new Dish("season fruit", true, 120, Dish.Type.OTHER),
            new Dish("pizza", true, 550, Dish.Type.OTHER),
            new Dish("salmon", false, 300, Dish.Type.FISH),
            new Dish("salmon", false, 450, Dish.Type.FISH) );

    public static void main(String[] args) {
        test2();
    }


    /**
     * Stream接口可以让你非常方便地处理它的元素：可以通过对
     * 收集源调用parallelStream方法来把集合转换为并行流。并行流就是一个把内容分成多个数据
     * 块，并用不同的线程分别处理每个数据块的流。这样一来，你就可以自动把给定操作的工作负荷
     * 分配给多核处理器的所有内核，让它们都忙起来
     */
    public static void test2(){
        int max = menu.parallelStream().map(Dish::getCalories).max(Integer::max).get();
        System.out.println(max);

        //并行流
        int max1 = menu.stream().parallel().map(Dish::getCalories).max(Integer::max).get();
        System.out.println(max);

        //串行流
        int max2 = menu.stream().sequential().map(Dish::getCalories).max(Integer::max).get();
        System.out.println(max);




    }

    /**
     * stream.parallel()
     * .filter(...)
     * .sequential()
     * .map(...)
     * .parallel()
     * .reduce();
     *
     * 但最后一次parallel或sequential调用会影响整个流水线。在本例中，流水线会并行执
     * 行，因为最后调用的是它。
     *
     *
     * 看看流的parallel方法，你可能会想，并行流用的线程是从哪儿来的？有多少个？怎么
     * 自定义这个过程呢？
     *
     * 并行流内部使用了默认的ForkJoinPool（7.2节会进一步讲到分支/合并框架），它默认的
     * 线程数量就是你的处理器数量， 这个值是由Runtime.getRuntime().available-
     * Processors()得到的。
     *
     * 工作窃取：
     * 分支/合并框架工程用一种称为工作窃取（work stealing）的技术来解决这个问题。在实际应
     * 用中，这意味着这些任务差不多被平均分配到ForkJoinPool中的所有线程上。每个线程都为分
     * 配给它的任务保存一个双向链式队列，每完成一个任务，就会从队列头上取出下一个任务开始执
     * 行。基于前面所述的原因，某个线程可能早早完成了分配给它的所有任务，也就是它的队列已经
     * 空了，而其他的线程还很忙。这时，这个线程并没有闲下来，而是随机选了一个别的线程，从队
     * 列的尾巴上“偷走”一个任务。这个过程一直继续下去，直到所有的任务都执行完毕，所有的队
     * 列都清空。这就是为什么要划成许多小任务而不是少数几个大任务，这有助于更好地在工作线程
     * 之间平衡负载
     */




}
